import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

public class Server
{
    private int receivePort;
    private ArrayList<TableServer> table;

    private HashMap<String, ArrayList<TableOffline>> offlinemsg;

    public Server(int receivePort)// gou zao function constructor
    {
        this.receivePort = receivePort;
        table = new ArrayList<TableServer>();
        offlinemsg = new HashMap<String, ArrayList<TableOffline>>();

    }

    public void run()
    {
        SendAndReceive test = new SendAndReceive(receivePort);// listen
        while (true)
        {
            DatagramPacket receive = test.receive(); // receive
            Packet packet = (Packet) Serializer.byteArrayToObject(receive.getData());
            if (packet.type == Packet.PacketType.Registration)
            {
                TableServer entry;
                entry = (TableServer) packet.data;
                InetAddress clientIp = receive.getAddress();
                byte[] clientIpByteArray = clientIp.getAddress();
                entry.clientIp = "";
                int i = 4;
                for (byte b : clientIpByteArray)
                {
                    entry.clientIp += (b & 0xFF);
                    if (--i > 0)
                        entry.clientIp += '.';
                }

                table.add(entry);
                System.out.println(entry.nickName + " Registration" + entry.clientIp);
                sendTable();

                ArrayList<TableOffline> msgs = offlinemsg.get(entry.nickName);
                if (msgs != null && !msgs.isEmpty())
                {
                    Packet packetmsg = new Packet();
                    packetmsg.type = Packet.PacketType.OfflineMsgs;
                    packetmsg.data = msgs;
                    SendAndReceive.send(packetmsg, entry.clientIp, entry.clientPort);
                    msgs.clear();
                }

            }

            if (packet.type == Packet.PacketType.DeRegistrating)
            {
                for (TableServer entrydee : table)// for each element
                                                  // "entry" in table
                {
                    if (entrydee.nickName.equals((String) packet.data))
                    {
                        entrydee.isOnline = false;
                    }
                    else
                    {

                    }
                }
                sendTable();
                for (TableServer entry : table)
                {
                    System.out.println(entry.nickName + entry.clientIp + ":" + entry.clientPort + ";" + entry.isOnline);
                }

                String a = "";
                int b = 0;
                for (TableServer entrydee : table)// for each element
                // "entry" in table
                {
                    if (entrydee.nickName.equals((String) packet.data))
                    {
                        a = entrydee.clientIp;
                        b = entrydee.clientPort;
                    }
                    else
                    {

                    }
                }

                Packet packetACK = new Packet();
                packetACK.type = Packet.PacketType.ACKdeg;
                packetACK.data = packet.data;
                SendAndReceive.send(packetACK, a, b);

            }

            if (packet.type == Packet.PacketType.Chatting)
            {
                // get receiver nickname from packet
                Msg offline = (Msg) packet.data;
                String receiver = offline.receiverNickName;

                // get the ArrayList<TableOffline> corresponding to receiver.
                // create one if not exists
                ArrayList<TableOffline> allmsg = offlinemsg.get(receiver);
                if (allmsg == null)
                {
                    allmsg = new ArrayList<TableOffline>();
                    offlinemsg.put(receiver, allmsg);
                }

                // create a TableOffline entry, don't forget to update timestamp

                TableOffline msg = new TableOffline(offline.senderNickName, new Date(), offline.msg);

                // Add the new entry to the ArrayList in step 2.
                allmsg.add(msg);

                System.out.println("OfflineMsg: from " + offline.senderNickName + " to " + offline.receiverNickName
                        + " : " + offline.msg);

                Packet packetACK = new Packet();
                packetACK.type = Packet.PacketType.ACK;
                for (TableServer abc : table)
                {
                    if (abc.nickName.equals(offline.senderNickName))
                        SendAndReceive.send(packetACK, abc.clientIp, abc.clientPort);

                }

            }

        }

    }

    public void sendTable()
    {
        Packet packet = new Packet();// construct a Packet to wrap table before
                                     // sending
        packet.type = packet.type.UpdateTable;
        packet.data = table;
        for (TableServer entry : table)// for each element "entry" in table
        {
            if (entry.isOnline)
            {
                SendAndReceive.send(packet, entry.clientIp, entry.clientPort);
            }
        }
        // send ArrayList<TableServer> to every client.
    }

}
